From e2b8c751654956aef727ec7ee17091cd8e0938ac Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Thu, 9 Mar 2006 16:24:57 +0000 Subject: [PATCH] Change the location of the shared_info page for auto_translated_physmap guests. Instead of putting the page outside of the guests pseudo-physical address space, we put it next to the other pages filled by the domain builder, such that the page is already mapped in the initial pagetables and/or a lowmem-type memory mapping. Signed-off-by: Christian Limpach --- linux-2.6-xen-sparse/arch/i386/mm/init-xen.c | 13 +- .../arch/x86_64/kernel/setup-xen.c | 7 + .../arch/x86_64/mm/init-xen.c | 12 +- .../asm-i386/mach-xen/setup_arch_post.h | 7 + tools/libxc/xc_linux_build.c | 139 +++++++++--------- xen/arch/x86/mm.c | 47 +++++- xen/common/memory.c | 65 ++++---- xen/include/public/memory.h | 15 ++ xen/include/xen/mm.h | 2 + 9 files changed, 201 insertions(+), 106 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/i386/mm/init-xen.c b/linux-2.6-xen-sparse/arch/i386/mm/init-xen.c index b490dbd2ec..02bcc6139a 100644 --- a/linux-2.6-xen-sparse/arch/i386/mm/init-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/mm/init-xen.c @@ -556,10 +556,15 @@ void __init paging_init(void) kmap_init(); - /* Switch to the real shared_info page, and clear the dummy page. */ - set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info); - HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO); - memset(empty_zero_page, 0, sizeof(empty_zero_page)); + if (!xen_feature(XENFEAT_auto_translated_physmap) || + xen_start_info->shared_info >= xen_start_info->nr_pages) { + /* Switch to the real shared_info page, and clear the + * dummy page. */ + set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info); + HYPERVISOR_shared_info = + (shared_info_t *)fix_to_virt(FIX_SHARED_INFO); + memset(empty_zero_page, 0, sizeof(empty_zero_page)); + } /* Setup mapping of lower 1st MB */ for (i = 0; i < NR_FIX_ISAMAPS; i++) diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c index 7827ee089c..c06c2b26a1 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c @@ -664,6 +664,13 @@ void __init setup_arch(char **cmdline_p) setup_xen_features(); + if (xen_feature(XENFEAT_auto_translated_physmap) && + xen_start_info->shared_info < xen_start_info->nr_pages) { + HYPERVISOR_shared_info = + (shared_info_t *)__va(xen_start_info->shared_info); + memset(empty_zero_page, 0, sizeof(empty_zero_page)); + } + HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables); diff --git a/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c b/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c index 0d09c4edbf..745c111a74 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c @@ -757,10 +757,16 @@ void __init paging_init(void) free_area_init_node(0, NODE_DATA(0), zones, __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes); - set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info); - HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO); + if (!xen_feature(XENFEAT_auto_translated_physmap) || + xen_start_info->shared_info >= xen_start_info->nr_pages) { + /* Switch to the real shared_info page, and clear the + * dummy page. */ + set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info); + HYPERVISOR_shared_info = + (shared_info_t *)fix_to_virt(FIX_SHARED_INFO); + memset(empty_zero_page, 0, sizeof(empty_zero_page)); + } - memset(empty_zero_page, 0, sizeof(empty_zero_page)); init_mm.context.pinned = 1; /* Setup mapping of lower 1st MB */ diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h index 4ae0de6be0..916b7ad385 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h @@ -37,6 +37,13 @@ static void __init machine_specific_arch_setup(void) struct xen_platform_parameters pp; struct xennmi_callback cb; + if (xen_feature(XENFEAT_auto_translated_physmap) && + xen_start_info->shared_info < xen_start_info->nr_pages) { + HYPERVISOR_shared_info = + (shared_info_t *)__va(xen_start_info->shared_info); + memset(empty_zero_page, 0, sizeof(empty_zero_page)); + } + HYPERVISOR_set_callbacks( __KERNEL_CS, (unsigned long)hypervisor_callback, __KERNEL_CS, (unsigned long)failsafe_callback); diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c index fe5cf69172..f5894d2724 100644 --- a/tools/libxc/xc_linux_build.c +++ b/tools/libxc/xc_linux_build.c @@ -606,15 +606,11 @@ static int setup_guest(int xc_handle, struct load_funcs load_funcs; struct domain_setup_info dsi; unsigned long vinitrd_start; - unsigned long vinitrd_end; unsigned long vphysmap_start; - unsigned long vphysmap_end; unsigned long vstartinfo_start; - unsigned long vstartinfo_end; unsigned long vstoreinfo_start; - unsigned long vstoreinfo_end; unsigned long vconsole_start; - unsigned long vconsole_end; + unsigned long vsharedinfo_start = 0; /* XXX gcc */ unsigned long vstack_start; unsigned long vstack_end; unsigned long vpt_start; @@ -640,6 +636,34 @@ static int setup_guest(int xc_handle, goto error_out; } + /* Parse and validate kernel features. */ + p = strstr(dsi.xen_guest_string, "FEATURES="); + if ( p != NULL ) + { + if ( !parse_features(p + strlen("FEATURES="), + supported_features, + required_features) ) + { + ERROR("Failed to parse guest kernel features.\n"); + goto error_out; + } + + printf("Supported features = { %08x }.\n", supported_features[0]); + printf("Required features = { %08x }.\n", required_features[0]); + } + + for ( i = 0; i < XENFEAT_NR_SUBMAPS; i++ ) + { + if ( (supported_features[i]&required_features[i]) != required_features[i] ) + { + ERROR("Guest kernel does not support a required feature.\n"); + goto error_out; + } + } + + shadow_mode_enabled = test_feature_bit(XENFEAT_auto_translated_physmap, + required_features); + /* * Why do we need this? The number of page-table frames depends on the * size of the bootstrap address space. But the size of the address space @@ -647,17 +671,22 @@ static int setup_guest(int xc_handle, * read-only). We have a pair of simultaneous equations in two unknowns, * which we solve by exhaustive search. */ - vinitrd_start = round_pgup(dsi.v_end); - vinitrd_end = vinitrd_start + initrd->len; - vphysmap_start = round_pgup(vinitrd_end); - vphysmap_end = vphysmap_start + (nr_pages * sizeof(unsigned long)); - vstartinfo_start = round_pgup(vphysmap_end); - vstartinfo_end = vstartinfo_start + PAGE_SIZE; - vstoreinfo_start = vstartinfo_end; - vstoreinfo_end = vstoreinfo_start + PAGE_SIZE; - vconsole_start = vstoreinfo_end; - vconsole_end = vconsole_start + PAGE_SIZE; - vpt_start = vconsole_end; + v_end = round_pgup(dsi.v_end); + vinitrd_start = v_end; + v_end += round_pgup(initrd->len); + vphysmap_start = v_end; + v_end += round_pgup(nr_pages * sizeof(unsigned long)); + vstartinfo_start = v_end; + v_end += PAGE_SIZE; + vstoreinfo_start = v_end; + v_end += PAGE_SIZE; + vconsole_start = v_end; + v_end += PAGE_SIZE; + if ( shadow_mode_enabled ) { + vsharedinfo_start = v_end; + v_end += PAGE_SIZE; + } + vpt_start = v_end; for ( nr_pt_pages = 2; ; nr_pt_pages++ ) { @@ -697,26 +726,22 @@ static int setup_guest(int xc_handle, #define _p(a) ((void *) (a)) - printf("VIRTUAL MEMORY ARRANGEMENT:\n" - " Loaded kernel: %p->%p\n" - " Init. ramdisk: %p->%p\n" - " Phys-Mach map: %p->%p\n" - " Start info: %p->%p\n" - " Store page: %p->%p\n" - " Console page: %p->%p\n" - " Page tables: %p->%p\n" - " Boot stack: %p->%p\n" - " TOTAL: %p->%p\n", - _p(dsi.v_kernstart), _p(dsi.v_kernend), - _p(vinitrd_start), _p(vinitrd_end), - _p(vphysmap_start), _p(vphysmap_end), - _p(vstartinfo_start), _p(vstartinfo_end), - _p(vstoreinfo_start), _p(vstoreinfo_end), - _p(vconsole_start), _p(vconsole_end), - _p(vpt_start), _p(vpt_end), - _p(vstack_start), _p(vstack_end), - _p(dsi.v_start), _p(v_end)); - printf(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry)); + printf("VIRTUAL MEMORY ARRANGEMENT:\n"); + printf(" Loaded kernel: %p->%p\n", _p(dsi.v_kernstart), + _p(dsi.v_kernend)); + if ( initrd->len ) + printf(" Initial ramdisk: %p->%p\n", _p(vinitrd_start), + _p(vinitrd_start + initrd->len)); + printf(" Phys-Mach map: %p\n", _p(vphysmap_start)); + printf(" Start info: %p\n", _p(vstartinfo_start)); + printf(" Store page: %p\n", _p(vstoreinfo_start)); + printf(" Console page: %p\n", _p(vconsole_start)); + if ( shadow_mode_enabled ) + printf(" Shared Info page: %p\n", _p(vsharedinfo_start)); + printf(" Page tables: %p\n", _p(vpt_start)); + printf(" Boot stack: %p\n", _p(vstack_start)); + printf(" TOTAL: %p->%p\n", _p(dsi.v_start), _p(v_end)); + printf(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry)); if ( ((v_end - dsi.v_start)>>PAGE_SHIFT) > nr_pages ) { @@ -742,36 +767,6 @@ static int setup_guest(int xc_handle, xc_handle, dom, page_array, &dsi); - /* Parse and validate kernel features. */ - p = strstr(dsi.xen_guest_string, "FEATURES="); - if ( p != NULL ) - { - if ( !parse_features(p + strlen("FEATURES="), - supported_features, - required_features) ) - { - ERROR("Failed to parse guest kernel features.\n"); - goto error_out; - } - - fprintf(stderr, "Supported features = { %08x }.\n", - supported_features[0]); - fprintf(stderr, "Required features = { %08x }.\n", - required_features[0]); - } - - for ( i = 0; i < XENFEAT_NR_SUBMAPS; i++ ) - { - if ( (supported_features[i]&required_features[i]) != required_features[i] ) - { - ERROR("Guest kernel does not support a required feature.\n"); - goto error_out; - } - } - - shadow_mode_enabled = test_feature_bit( - XENFEAT_auto_translated_physmap, required_features); - if ( load_initrd(xc_handle, dom, initrd, vinitrd_start - dsi.v_start, page_array) ) goto error_out; @@ -869,6 +864,7 @@ static int setup_guest(int xc_handle, if ( shadow_mode_enabled ) { struct xen_reserved_phys_area xrpa; + struct xen_map_shared_info xmsi; /* Enable shadow translate mode */ if ( xc_shadow_control(xc_handle, dom, @@ -889,7 +885,16 @@ static int setup_guest(int xc_handle, PERROR("Cannot find shared info pfn"); goto error_out; } - guest_shared_info_mfn = xrpa.first_gpfn; + + guest_shared_info_mfn = (vsharedinfo_start-dsi.v_start) >> PAGE_SHIFT; + xmsi.domid = dom; + xmsi.pfn = guest_shared_info_mfn; + rc = xc_memory_op(xc_handle, XENMEM_map_shared_info, &xmsi); + if ( rc != 0 ) + { + PERROR("Cannot map shared info pfn"); + goto error_out; + } } else { diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 1994ecb8c9..fd6f323514 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -2817,14 +2817,15 @@ long do_update_descriptor(u64 pa, u64 desc) long arch_memory_op(int op, GUEST_HANDLE(void) arg) { - struct xen_reserved_phys_area xrpa; unsigned long pfn; struct domain *d; unsigned int i; switch ( op ) { - case XENMEM_reserved_phys_area: + case XENMEM_reserved_phys_area: { + struct xen_reserved_phys_area xrpa; + if ( copy_from_guest(&xrpa, arg, 1) ) return -EFAULT; @@ -2846,16 +2847,14 @@ long arch_memory_op(int op, GUEST_HANDLE(void) arg) if ( d->arch.first_reserved_pfn == 0 ) { d->arch.first_reserved_pfn = pfn = d->max_pages; - guest_physmap_add_page( - d, pfn + 0, virt_to_maddr(d->shared_info) >> PAGE_SHIFT); for ( i = 0; i < NR_GRANT_FRAMES; i++ ) guest_physmap_add_page( - d, pfn + 1 + i, gnttab_shared_mfn(d, d->grant_table, i)); + d, pfn + i, gnttab_shared_mfn(d, d->grant_table, i)); } UNLOCK_BIGLOCK(d); xrpa.first_gpfn = d->arch.first_reserved_pfn; - xrpa.nr_gpfns = 32; + xrpa.nr_gpfns = NR_GRANT_FRAMES; put_domain(d); @@ -2863,6 +2862,42 @@ long arch_memory_op(int op, GUEST_HANDLE(void) arg) return -EFAULT; break; + } + + case XENMEM_map_shared_info: { + struct xen_map_shared_info xmsi; + + if ( copy_from_guest(&xmsi, arg, 1) ) + return -EFAULT; + + if ( (d = find_domain_by_id(xmsi.domid)) == NULL ) + return -ESRCH; + + /* Only initialised translated guests can set the shared_info + * mapping. */ + if ( !shadow_mode_translate(d) || (d->max_pages == 0) ) + { + put_domain(d); + return -ESRCH; + } + + if ( xmsi.pfn > d->max_pages ) { + put_domain(d); + return -EINVAL; + } + + LOCK_BIGLOCK(d); + /* Remove previously mapped page if it was present. */ + if ( mfn_valid(gmfn_to_mfn(d, xmsi.pfn)) ) + guest_remove_page(d, xmsi.pfn); + guest_physmap_add_page(d, xmsi.pfn, + virt_to_maddr(d->shared_info) >> PAGE_SHIFT); + UNLOCK_BIGLOCK(d); + + put_domain(d); + + break; + } default: return subarch_memory_op(op, arg); diff --git a/xen/common/memory.c b/xen/common/memory.c index eb0c68cac4..35072e5807 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -137,7 +137,43 @@ populate_physmap( out: return i; } - + +int +guest_remove_page( + struct domain *d, + unsigned long gmfn) +{ + struct page_info *page; + unsigned long mfn; + + mfn = gmfn_to_mfn(d, gmfn); + if ( unlikely(!mfn_valid(mfn)) ) + { + DPRINTK("Domain %u page number %lx invalid\n", + d->domain_id, mfn); + return 0; + } + + page = mfn_to_page(mfn); + if ( unlikely(!get_page(page, d)) ) + { + DPRINTK("Bad page free for domain %u\n", d->domain_id); + return 0; + } + + if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) ) + put_page_and_type(page); + + if ( test_and_clear_bit(_PGC_allocated, &page->count_info) ) + put_page(page); + + guest_physmap_remove_page(d, gmfn, mfn); + + put_page(page); + + return 1; +} + static long decrease_reservation( struct domain *d, @@ -147,8 +183,7 @@ decrease_reservation( unsigned int flags, int *preempted) { - struct page_info *page; - unsigned long i, j, gmfn, mfn; + unsigned long i, j, gmfn; if ( !guest_handle_okay(extent_list, nr_extents) ) return 0; @@ -166,30 +201,8 @@ decrease_reservation( for ( j = 0; j < (1 << extent_order); j++ ) { - mfn = gmfn_to_mfn(d, gmfn + j); - if ( unlikely(!mfn_valid(mfn)) ) - { - DPRINTK("Domain %u page number %lx invalid\n", - d->domain_id, mfn); + if ( !guest_remove_page(d, gmfn + j) ) return i; - } - - page = mfn_to_page(mfn); - if ( unlikely(!get_page(page, d)) ) - { - DPRINTK("Bad page free for domain %u\n", d->domain_id); - return i; - } - - if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) ) - put_page_and_type(page); - - if ( test_and_clear_bit(_PGC_allocated, &page->count_info) ) - put_page(page); - - guest_physmap_remove_page(d, gmfn + j, mfn); - - put_page(page); } } diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h index f3f16fe37c..723131548a 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -140,6 +140,21 @@ typedef struct xen_translate_gpfn_list { } xen_translate_gpfn_list_t; DEFINE_GUEST_HANDLE(xen_translate_gpfn_list_t); +/* + * Sets the GPFN at which the shared_info_page appears in the specified + * guest's pseudophysical address space. + * arg == addr of xen_map_shared_info_t. + */ +#define XENMEM_map_shared_info 9 +typedef struct xen_map_shared_info { + /* Which domain to change the mapping for. */ + domid_t domid; + + /* GPFN where the shared_info_page should appear. */ + unsigned long pfn; +} xen_map_shared_info_t; +DEFINE_GUEST_HANDLE(xen_map_shared_info_t); + #endif /* __XEN_PUBLIC_MEMORY_H__ */ /* diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h index b478f91700..ecd202d8a4 100644 --- a/xen/include/xen/mm.h +++ b/xen/include/xen/mm.h @@ -82,4 +82,6 @@ extern struct list_head page_scrub_list; #define sync_pagetable_state(d) ((void)0) #endif +int guest_remove_page(struct domain *d, unsigned long gmfn); + #endif /* __XEN_MM_H__ */ -- 2.30.2